package com.tree.rpc.netty.consumer.proxy;

import com.tree.rpc.netty.core.msg.InvokeMsg;
import com.tree.rpc.netty.registry.RegistryHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @ClassName com.tree.rpc.netty.consumer.proxy
 * Description: <类功能描述>. <br>
 * <p>
 * <使用说明>
 * </p>
 * @Author tree
 * @Date 2019-11-06 22:02
 * @Version 1.0
 */
public class RpcProxy {

    public static <T> T create(Class<?> clazz) {
        MethodProxy methodProxy = new MethodProxy(clazz);
        T result = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, methodProxy);
        return result;

    }
}

class MethodProxy implements InvocationHandler {

    private Class<?> clazz;

    public MethodProxy(Class<?> clazz) {
        this.clazz = clazz;
    }

    /**
     * 代理，调用IRpcHello接口中每一个方法的时候，实际上就是发起一次网络请求
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //如果传进来的是一个已经实现的具体的类（直接忽略）
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } else {//如果传进来的是一个接口，我们就走远程调用
            return rpcInvoke(method, args);
        }
    }

    public Object rpcInvoke(Method method, Object[] args) {
        EventLoopGroup group = new NioEventLoopGroup();

        InvokeMsg invokeMsg = new InvokeMsg();
        invokeMsg.setFullClassName(this.clazz.getName());
        invokeMsg.setMethodName(method.getName());
        invokeMsg.setParams(method.getParameterTypes());
        invokeMsg.setValues(args);

        final RpcProxyHandler handler = new RpcProxyHandler();

        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 4)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //处理拆包、粘包的解编码器
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));

                            //处理序列化的解编码器（JDK默认的序列化）
                            pipeline.addLast("encoder", new ObjectEncoder());
                            pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));


                            //自己的业务逻辑
                            pipeline.addLast("myhandle", handler);
                        }
                    });

            ChannelFuture future = b.connect("localhost", 8080).sync();
            future.channel().writeAndFlush(invokeMsg);

            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }


        return handler.getResult();

    }
}
